#include <am.h>
#include <klib-macros.h>

void __am_timer_init();

void __am_timer_rtc(AM_TIMER_RTC_T *);
void __am_timer_uptime(AM_TIMER_UPTIME_T *);

void __am_input_keybrd(AM_INPUT_KEYBRD_T *);

#define VGACTL_WIDTH 640
#define VGACTL_HEIGHT 480

void __am_gpu_config(AM_GPU_CONFIG_T *cfg)
{
  *cfg = (AM_GPU_CONFIG_T){
      .present = true, .has_accel = false, .width = VGACTL_WIDTH, .height = VGACTL_HEIGHT, .vmemsz = 0};
}

void __am_gpu_status(AM_GPU_STATUS_T *status)
{
  status->ready = true;
}

void __am_gpu_fbdraw(AM_GPU_FBDRAW_T *ctl)
{
}

static void __am_uart_tx(AM_UART_TX_T *send)
{
  putch(send->data);
}

static void __am_uart_rx(AM_UART_RX_T *recv)
{
  recv->data = 0;
}

static void __am_timer_config(AM_TIMER_CONFIG_T *cfg)
{
  cfg->present = true;
  cfg->has_rtc = true;
}
static void __am_input_config(AM_INPUT_CONFIG_T *cfg) { cfg->present = true; }

static void __am_uart_config(AM_UART_CONFIG_T *cfg) { cfg->present = true; }

typedef void (*handler_t)(void *buf);
static void *lut[128] = {
    [AM_UART_CONFIG] = __am_uart_config,
    [AM_UART_TX] = __am_uart_tx,
    [AM_UART_RX] = __am_uart_rx,

    [AM_TIMER_CONFIG] = __am_timer_config,
    [AM_TIMER_RTC] = __am_timer_rtc,
    [AM_TIMER_UPTIME] = __am_timer_uptime,

    [AM_INPUT_CONFIG] = __am_input_config,
    [AM_INPUT_KEYBRD] = __am_input_keybrd,

    [AM_GPU_CONFIG] = __am_gpu_config,
    [AM_GPU_FBDRAW] = __am_gpu_fbdraw,
    [AM_GPU_STATUS] = __am_gpu_status,
};

static void fail(void *buf) { panic("access nonexist register"); }

bool ioe_init()
{
  for (int i = 0; i < LENGTH(lut); i++)
    if (!lut[i])
      lut[i] = fail;
  __am_timer_init();
  return true;
}

void ioe_read(int reg, void *buf) { ((handler_t)lut[reg])(buf); }
void ioe_write(int reg, void *buf) { ((handler_t)lut[reg])(buf); }
